<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<?php
 include ('../include.php');
 include ('activityobj.php');
?>
<html>
<head>
<title>Critical Path Drawer</title>
<style>
button {
font-family:arial;
font-size: 12px;
padding: 1px;
-webkit-border-radius: 11.35135135135135px;
-moz-border-radius: 11.35135135135135px;
border-radius: 11.35135135135135px;
border-style:solid;
border-color:white;
color:white;
background:#3f3f3f;
}
button:focus {
outline: 0;
padding: 1px;
background:#FF1010;
border-style:solid;
border-color:white;
}
.b {
}
button.notstarted {background:#000000;}
button.started {background:#00aF00;}
button.finished {background:#AFAFAF;}

span {
 display:block;
}
.st {
font-family:arial;
font-size: 12px;
padding: 1px;
-webkit-border-radius: 11.35135135135135px;
-moz-border-radius: 11.35135135135135px;
border-radius: 11.35135135135135px;
background:#FF1010;
border-style:solid;
border-color:white;
color:white;
height:30px;
width:100px;
}
</style>
</head>
<body>
 
<div id='svgcont' style='height:70%;background:#cfcfcf;overflow:scroll;' ondragover="return false;">
<svg id='svgbit'>
 
</svg>
</div>
 

<table>
<tr>
<td>
<span class='st' id='Studio' draggable=true  ondragstart='dragstart()'>Studio Task</span>
<span class='st' id='Production' draggable=true ondragstart='dragstart()'>Production Task</span>
<span class='st' id='Packing' draggable=true ondragstart='dragstart()'>Packing Task</span>
<span class='st' id='Invoicing' draggable=true  ondragstart='dragstart()'>Invoicing Task</span>
</td>
<td>
<span class='st' ondragstart='dragstart()'>Copy Task Template</span>
<span class='st' onclick='saveit()'>Save</span>
</td>
</tr>
</table>


<script>

document.getElementById('svgcont').addEventListener('drop', dodrop, false);
  //TODO
  // Conditionally allow change of status based on dependence.
  // Instructions pop-out window
  // Tie to consistent job number
 /*
 Data structure
  Work : Itemid. Name. Duration. Type. Job. (X/Y ?)
  Workdepends. id. dependent.
 */
  var _ex = 0;
  var _ey = 0 ;
  var counter = new Date().getTime() * 1000;
  
  var snaptogrid = true ;
 
  function dodrop(ev) {
    var src = ev.dataTransfer.getData("Text");
    if (src == 'Production' || src == 'Studio') {
      var lnk = makenew(ev);
      lnk.childNodes[3].innerHTML = src;      
      document.getElementById('svgcont').appendChild(lnk);
    } else if (getel(src,0) == 'ACTIVITY') {
      if (ev.shiftKey) {
        attachnew(ev);
      } else {
        movebox(ev);
      }
    } else {
      alert("I don't know what to do! " + src);
    }
  }
 
  function saveit() {
   // Make up a URL
   var all = document.getElementsByTagName("button");
   var activity = {} ;
   
   for (var i=0, max=all.length; i < max; i++) {
    if (getel(all[i].id,0) == 'ACTIVITY') {
     var nodeitem = document.getElementById(all[i].id);          
     activity[all[i].id] =
     [
      getel(nodeitem.id,1),
      nodeitem.childNodes[3].innerHTML,
      nodeitem.myeditversion,
      nodeitem.myeditdate,
      nodeitem.myeditby,
      nodeitem.myempid,
      nodeitem.myprocessid,
      nodeitem.className,
      nodeitem.myjobid,
      nodeitem.myschedulestarttime,
      nodeitem.childNodes[1].innerHTML,
      nodeitem.style.left,
      nodeitem.style.top
     ]
    }
   }

   var activitydepends = [] ;
 
   all = document.getElementsByTagNameNS("http://www.w3.org/2000/svg","line");
   for (var i=0, max=all.length; i < max; i++) {
    if (getel(all[i].id,0) == 'LINE') {
     var lineend = getel(all[i].id,2);
     var linestart = getel(all[i].id,1);
     // Swap ends if left < right
     if (document.getElementById('ACTIVITY|'+lineend).offsetLeft < document.getElementById('ACTIVITY|'+linestart).offsetLeft) {
      var lineend = getel(all[i].id,1);
      var linestart = getel(all[i].id,2);
     }
     activitydepends.push([lineend,linestart]);
    }  
   }


   var url = '?activity='+encodeURIComponent(JSON.stringify(activity))+'&activitydepends='+encodeURIComponent(JSON.stringify(activitydepends));
   window.location = url ;
  }

  function movebox(ev) {
    var src = ev.dataTransfer.getData("Text");
    obj = document.getElementById(src);
    if (snaptogrid) {
     obj.style.left = Math.floor((ev.x)/120)*120+10;
     obj.style.top = Math.floor((ev.y)/80)*80+10;
    } else {
     obj.style.left = Math.max(0,ev.x-_ex);
     obj.style.top = Math.max(0,ev.y-_ey);
    }

    var activityid = getel(src,1);
    // find any lines pointing to this box. Delete them and call drawlinebetweenboxes
    li = document.getElementById('svgbit').childNodes;
    otherboxes = new Array();
    for (var i = li.length - 1; i >= 0; i--) {
      
      if (li[i].id && getel(li[i].id,0) == 'LINE') {
       if (getel(li[i].id,1) == activityid || getel(li[i].id,2) == activityid) {
        otherboxes.push(li[i].id);
        li[i].parentNode.removeChild(li[i]);
       }
      }
    }
    for (var i = otherboxes.length - 1; i >= 0; i--) {
      boxlist = otherboxes[i].split('|');
      drawlinebetweenboxes(document.getElementById('ACTIVITY|'+boxlist[1]), document.getElementById('ACTIVITY|'+boxlist[2]));
    }
    calccpath();
  }
 
  function droponbox(ev, dest) {
    // Make a link
    src = ev.dataTransfer.getData("Text");
    dest = dest.id;
    var oldobj = document.getElementById(src);
    var newobj = document.getElementById(dest);
    if (getel(oldobj.id,0) == 'ACTIVITY') {
     // line start point is going to be to the left of largest of the two x values.
     drawlinebetweenboxes(oldobj, newobj);  
     calccpath();
    }
    
    event.stopPropagation();
    return false;
  }
 
  function clickedonline(el) {
    el.parentNode.removeChild(el);
    calccpath();
  }
  
  function clickedondur(ev,el) {
    ans = window.prompt('Enter Duration', el.id);
    if (!isNaN(ans) && ans != '') {
     el.innerHTML = ans;
     calccpath();     
    }
    event.stopPropagation();
    return false;
 
  }
 
  function clickedonbox(ev, el) {
    if (ev.ctrlKey) {
      // Delete the box along with any lines that connect to it
      boxid = el.id;
      li = document.getElementById('svgbit').childNodes;
      for (var i = li.length - 1; i >= 0; i--) {
        if (li[i].id && getel(li[i].id,0) == 'LINE') {
         if ('ACTIVITY|'+getel(li[i].id,1) == boxid || 'ACTIVITY|'+getel(li[i].id,2) == boxid) {
          li[i].parentNode.removeChild(li[i]);
         }
        }
      }
      el.parentNode.removeChild(el);
      calccpath();     
    } else if (ev.shiftKey) {
      ans = window.prompt('Enter Description', el.childNodes[3].innerHTML );
      el.childNodes[3].innerHTML = ans ;
      event.stopPropagation();
      return false ;  
    
    }else {
     recolor(el);
    }
  }
  

  function attachnew(ev) {
    // Create a new box attached to the one we are dragging from
    var src = ev.dataTransfer.getData("Text");
    var oldobj = document.getElementById(src);
    var newobj = makenew(ev);

    newobj.childNodes[3].innerHTML = oldobj.childNodes[3].innerHTML;      
    document.getElementById('svgcont').appendChild(newobj);
    drawlinebetweenboxes(oldobj, newobj);
    calccpath();         
  }
 
  function drawlinebetweenboxes(box1, box2) {
    // Can't join box to itself
    if (box1 == box2) {
      return;
    }
    // Check this link doesn't already exist ;
    li = document.getElementById('svgbit').childNodes;
    for (var i = li.length - 1; i >= 0; i--) {
      lineid = li[i].id;
      if (lineid == 'LINE|'+getel(box1.id,1)+'|'+getel(box2.id,1) || lineid == 'LINE|'+getel(box2.id,1)+'|'+getel(box1.id,1)) {
        return;
      }
    }
    var x1 = numpix(box1.style.left);
    var y1 = numpix(box1.style.top) + 25;
    var x2 = numpix(box2.style.left);
    var y2 = numpix(box2.style.top) + 25;
    if (x2 > x1) {
      x1 = x1 + 50;
    } else {
      x2 = x2 + 50;
    }
    var sv = document.getElementById('svgbit');
    var ln = document.createElementNS("http://www.w3.org/2000/svg", 'line');
    ln.setAttribute('x1', x1);
    ln.setAttribute('x2', x2);
    ln.setAttribute('y1', y1);
    ln.setAttribute('y2', y2);
    ln.id = 'LINE|' + getel(box1.id,1) + '|' + getel(box2.id,1);
    ln.style.stroke = '#00a0ff';
    ln.onclick = function() {
      clickedonline(this);
    };
    ln.style.strokeWidth = '10px';
    sv.appendChild(ln);
  }
 

 
  function makenew(ev) {
    // Create a new box at ev.x, ev.y
    var lnk = document.createElement('button');
    lnk.id = 'ACTIVITY|' + counter++;
    lnk.setAttribute('name', lnk.id);
    lnk.setAttribute('value','||||||||');
    lnk.draggable = true;
    lnk.ondrop = function() {
      droponbox(event, this);
    };
    lnk.ondragstart = function() {
      dragstart();
    };
    lnk.style.height = '70px';
    lnk.style.width = '100px';
    lnk.style.position = 'absolute';
    lnk.style.display = 'inline-block';
    lnk.onclick = function() {
      clickedonbox(event, this);
      return false;
    };

    if (ev) {
     if (snaptogrid) {
      lnk.style.left = Math.floor((ev.x)/120)*120+10;
      lnk.style.top = Math.floor((ev.y)/80)*80+10;
     } else {
      lnk.style.left = ev.x-_ex;
      lnk.style.top = ev.y-_ey;
     }
    } else {
     lnk.style.left = _ex;
     lnk.style.top = _ey;
    }

    var btn = document.createElement('button');
    btn.setAttribute('name','est');
    btn.type = 'button';
    btn.innerHTML = '0';
    btn.title = 'Earliest Start';
    lnk.appendChild(btn);

    var btn = document.createElement('button');
    btn.setAttribute('name','dur');
    btn.type = 'button';
    btn.title = 'Duration';
    btn.innerHTML = '1';
    btn.onclick = function() {
      clickedondur(event,this);
      return false;
    };
    lnk.appendChild(btn);

    var btn = document.createElement('button');
    btn.setAttribute('name','eft');
    btn.type = 'button';
    btn.title = 'Earliest Finish';
    btn.innerHTML = '0';
    lnk.appendChild(btn);

    var bt = document.createElement('span');
    bt.innerHTML = lnk.id;
    lnk.appendChild(bt);

    var btn = document.createElement('button');
    btn.setAttribute('name','lst');
    btn.type = 'button';
    btn.innerHTML = '0';
    btn.title = 'Latest Start';
    lnk.appendChild(btn);

    var btn = document.createElement('button');
    btn.setAttribute('name','lft');
    btn.type = 'button';
    btn.innerHTML = '0';
    btn.title = 'Latest Finish';
    lnk.appendChild(btn);

    lnk.className = 'notstarted' ;
    lnk.myeditversion = '0';
    lnk.myeditdate = '2014-01-01';
    lnk.myeditby = 'AJL';
    lnk.myempid = '';
    lnk.myprocessid = '';
    lnk.mystatus = '';
    lnk.myjobid = '';
    lnk.myschedulestarttime = '';
    return lnk;
  }
 
  function recolor(el) {  
   
   if (el.className == 'notstarted') {
    el.className = 'started';
   } else if (el.className == 'started') {
    el.className = 'finished';
   } else {
    el.className = 'notstarted';
   }
  }

  function dragstart() {
    _ex = event.x-event.srcElement.offsetLeft ;
    _ey = event.y-event.srcElement.offsetTop ;
    event.dataTransfer.setData("Text", event.srcElement.id);
  }
  ///////////////////////////////////////////Helpers/////////////////////
 
   function findimpliedlines(lineends) {
    // Where a->b and b->c and a->c we need to delete a->c
    var impliedlist = [] ;
    for (var node in lineends) {
     var nodelist = [];
     var level = 0 ;
     makeallends(lineends,node,node,nodelist,level,impliedlist);
    }
    return impliedlist ;
  }
  
  function makeallends(lineends,supernode,parentnode,nodelist,level,impliedlist) {
   for (var i=0, max=lineends[parentnode].length; i < max; i++) {
    var child = lineends[parentnode][i] ;
    if (nodelist.indexOf(child) != -1)  nodelist.push(child) ;
    if (lineends[supernode].indexOf(child) != -1 && level !=0) {
     impliedlist.push(supernode+'|'+child) ;
    }
    if (child in lineends) {
     makeallends(lineends,supernode,child,nodelist,level+1,impliedlist);
    }
   }
  }
  

  function calccpath() {

   // Lets make a list of all of the nodes
   var all = document.getElementsByTagName("button");
   var nodes = {} ;
       
   for (var i=0, max=all.length; i < max; i++) {
    if (getel(all[i].id,0) == 'ACTIVITY') {
     var nodeitem = document.getElementById(all[i].id);
     var duration = nodeitem.childNodes[1].innerHTML ;
     nodes[all[i].id] = {dur:duration} ;
    }   
   }
 
   // Make a list of all of the lines indexed by start or end position
   all = document.getElementsByTagNameNS("http://www.w3.org/2000/svg","line");
   var lineends = {};
   var linestarts = {};
   var alllines = [] ;
   
   for (var i=0, max=all.length; i < max; i++) {
    if (getel(all[i].id,0) == 'LINE') {
     alllines.push(all[i].id);
     var lineend = 'ACTIVITY|' + getel(all[i].id,2);
     var linestart = 'ACTIVITY|' + getel(all[i].id,1);
     // Swap ends if left < right
     if (document.getElementById(lineend).offsetLeft < document.getElementById(linestart).offsetLeft) {
      var temp = lineend ;
      lineend = linestart;
      linestart = temp ;
     }
 
     if (!(lineend in lineends)) lineends[lineend] = [] ;
     lineends[lineend].push(linestart);
 
     if (!(linestart in linestarts)) linestarts[linestart] = [] ;
     linestarts[linestart].push(lineend);
 
    }  
   }
   var impliedlist = findimpliedlines(lineends);
   maxit = 1 ;
   // Traverse the nodes. If everything pointing to this node has an eft then we can give this node an eft.
   newnodelist = nodes ;
   while (Object.keys(newnodelist).length != 0 && maxit < 50 ) {
    maxit = maxit + 1 ;
    failednodelist = {} ;
    for (var nodename in newnodelist) {
     var success = true ;
     if (!(nodename in lineends)) {
      var eft = 0 ;
     } else {
      // Go through whatever points here
      var eft = 0 ;
      for (var i=0, max=lineends[nodename].length; i < max; i++) {
       linestart = lineends[nodename][i];
       var eftpoints = nodes[linestart].eft ;
       if (eftpoints) {
        if (eftpoints > eft) eft = eftpoints ;
       } else {
        success = false;
       }
      }
     }
 
     if (success) {
      nodes[nodename].eft = eft*1 + nodes[nodename].dur*1;
      document.getElementById(nodename).childNodes[2].innerHTML = nodes[nodename].eft;
      document.getElementById(nodename).childNodes[0].innerHTML = nodes[nodename].eft  - nodes[nodename].dur*1 ;
     } else {
      failednodelist[nodename] = nodes[nodename];
     }
    }
    newnodelist = failednodelist ;
   }


   // Traverse in reverse to set lfts. 

   maxit = 1 ;
   newnodelist = nodes ;
   while(Object.keys(newnodelist).length != 0 && maxit < 50) {
    maxit = maxit + 1 ;
    failednodelist = {}; 
    for (var nodename in newnodelist) {
     var success = true ;
     if (!(nodename in linestarts)) {
      var lft = document.getElementById(nodename).childNodes[2].innerHTML ;
     } else {
      // Go through everything this points to
      var lft = 999999 ;
      for (var i=0,max=linestarts[nodename].length; i < max;i++) {
       lineend = linestarts[nodename][i];
       var lstpoints = nodes[lineend].lst ;
       if (lstpoints) {
        if (lstpoints < lft) lft = lstpoints ;
       } else {
        success = false; 
       }
      }
     }

     if (success) {
      nodes[nodename].lst = lft*1 - nodes[nodename].dur*1 ;
      document.getElementById(nodename).childNodes[4].innerHTML = nodes[nodename].lst ;
      document.getElementById(nodename).childNodes[5].innerHTML = nodes[nodename].lst + nodes[nodename].dur*1;
     } else {
      failednodelist[nodename] = nodes[nodename];
     }
    }
    newnodelist = failednodelist;
   }

   // Colour the critical path
   // Only nodes can be critical. Paths can't be as they don't occupy any time.
   // So we color the as being critical only where the node at each end of that line is critical

    for (var i=0, max = alllines.length; i < max; i++) {
     var endnode = document.getElementById('ACTIVITY|'+getel(alllines[i],1));
     var startnode = document.getElementById('ACTIVITY|'+getel(alllines[i],2));
     if (impliedlist.indexOf(endnode.id+'|'+startnode.id) != -1 || impliedlist.indexOf(startnode.id+'|'+endnode.id) != -1) {
      document.getElementById(alllines[i]).style.stroke = '#A0A0A0';
     } else if (endnode.childNodes[0].innerHTML == endnode.childNodes[4].innerHTML && startnode.childNodes[0].innerHTML == startnode.childNodes[4].innerHTML) {
      document.getElementById(alllines[i]).style.stroke = '#FF0000';
     } else {
      document.getElementById(alllines[i]).style.stroke = '#0000FF';
     }
    }

  }
 
  function getel(str, pos) {
    // Helper returns the nth element of a string delimited with |. It seems that dataset wont store arrays
    var a = str.split('|');
    return a[pos];
  }
 
  function numpix(txt) {
    // Helper to remove the px bit from sizes so we can do maths
    var p = txt.indexOf('px');
    var subtxt = txt.substring(0, p);
    return subtxt * 1;
  }
</script>
 
</body>
</html>
<?php
  if ($activity = @$_REQUEST['activity']) {

   $activitydepends = @$_REQUEST['activitydepends'] ;
   $activityobj = new activity() ;
   if ($activitydepends == '') {$activitydepends = '[]';}
   $activityobj->writefromrequest($activity,$activitydepends);
   list($activity,$activitydepends) = $activityobj->readjob('') ;

   echo "
<script>

function drawpath(arr) {
 for (activityid in arr) {
  var activity = arr[activityid];
  var lnk = makenew();
  lnk.id = 'ACTIVITY|'+activityid ;
  lnk.childNodes[3].innerHTML = activity[1];
  lnk.myeditversion = activity[2];
  lnk.myeditdate = activity[3];
  lnk.myeditby = activity[4];
  lnk.myempid = activity[5];
  lnk.myprocessid = activity[6];
  lnk.className = activity[7];
  lnk.myjobid = activity[8];
  lnk.myschedulestarttime = activity[9]; 
  lnk.childNodes[1].innerHTML = activity[10];
  lnk.style.left = activity[11];
  lnk.style.top = activity[12];
  document.getElementById('svgcont').appendChild(lnk); 
 }
}

function drawlines(arr) {
 for (var i=0,max=arr.length; i < max;i++) {
  drawlinebetweenboxes(document.getElementById('ACTIVITY|'+arr[i][0]),document.getElementById('ACTIVITY|'+arr[i][1]));
 }
}

var arr = $activity ;
drawpath(arr);
console.log(JSON.stringify(arr));
var arr = $activitydepends;
drawlines(arr);
console.log(JSON.stringify(arr));
calccpath();
</script>";
}
 
?> 